'''
    @project: Masdevallia
    @author: Austin Baker
    @created: 2/22/2014
    @license: http://opensource.org/licenses/mit-license.php

    The MIT License (MIT)

    Copyright (c) 2014 Austin Baker
    
    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:
    
    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.
    
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    THE SOFTWARE.
    
    ------
    
    About:
'''

import math

import maya.cmds as CMDS
import maya.OpenMaya as OpenMaya

import masdevallia.nodes.Node as Node
import masdevallia.utility.Dag as Dag
import masdevallia.utility.Matrix as Matrix

class RigModuleMarker( object ):
    '''
    Rig marker object. Used in the creation of a rigging module.
    '''
    def __init__( self, name=None ):
        # Marker properties.
        self.name = name
        self.mobject = None
        self.mdagpath = None
        
        # Control properties.
        self.control_name = None
        self.control_type = None
        self.control_cvs = None
        
        # Joint properties.
        self.joint_name = None
        
        # Parent proxy properties.
        self.parent_proxy = None
        
        # Module root.
        self.module_root = None
    
    def createMarker( self, parent=None ):
        '''
        Creates the marker polygon geometry.
        
        radius: limbs,spine,etc=6 fingers=4
        
        @param parent: MObject.
        '''
        # Make sure we have the shaders.
        self.createShaders()
        
        # A list to store each polygon object created. This is used
        # later to create a compound object.
        poly_objects = []
                
        # Make the sphere. Returns a list [transform name, poly input]
        node = CMDS.polySphere( name=self.name, subdivisionsX=8, subdivisionsY=4, radius=6 )[0]
        self.mobject = Dag.getMObject( node )
        self.mdagpath = Dag.getDagPath( self.mobject )
        
        # Apply the correct wireframe color.            
        self.setShapeColor( self.mobject, 'body' )
        
        # Add it to the poly list.
        poly_objects.append( str(node) )
        
        # Create the axis pointers.
        axes = [ 'x', 'y', 'z' ]
        for axis in axes:
            cone_name = '{0}_{1}'.format( self.name, axis )
            cone = CMDS.polyCone( name=cone_name, radius=2, height=20, subdivisionsX=4, subdivisionsY=1, subdivisionsZ=0 )[0]
            cone_mobject = Dag.getMObject( str(cone) )
            cone_mdagpath = Dag.getDagPath( cone_mobject )
            cone_matrix = Matrix.Matrix( str(cone), 'worldMatrix' )
            
            # Move it into position.
            if axis == 'x':
                trans_vector = OpenMaya.MVector( 13, 0, 0 )
            elif axis == 'y':
                trans_vector = OpenMaya.MVector( 0, 13, 0 )
            elif axis == 'z':
                trans_vector = OpenMaya.MVector( 0, 0, 13 )
                
            cone_matrix.translateBy( trans_vector, cone_matrix.worldSpace )
            
            # Rotate it into position.
            if axis == 'x':
                rotation = OpenMaya.MEulerRotation( OpenMaya.MVector( 0, 0, math.radians(-90) ) )
            elif axis == 'y':
                rotation = OpenMaya.MEulerRotation( OpenMaya.MVector( 0, 0, 0 ) )
            elif axis == 'z':
                rotation = OpenMaya.MEulerRotation( OpenMaya.MVector( math.radians(90), 0, 0 ) )
                    
            cone_matrix.rotateBy( rotation )
            
            # Apply the correct wireframe color.            
            self.setShapeColor( cone_mobject, axis )
            
            # Add it to the list.
            poly_objects.append( str(cone) )
            
            # Freeze the transform of the cone.
            CMDS.makeIdentity( str(cone), apply=True, translate=True, rotate=True, scale=True, normal=False, preserveNormals=True )
            
        # Combine the shapes under one transform.
        marker_node = self.createCompound( poly_objects )
        
        # Do the parenting.
        if parent is not None:
            mdag_mod = OpenMaya.MDagModifier()
            mdag_mod.reparentNode( marker_node.asMObject(), parent )
            mdag_mod.doIt()
        
        # Add the plugs for this marker.
        Dag.createPlug( self.mobject, 'metaNode', 'mn', 'string' )
        Dag.createPlug( self.mobject, 'controlName', 'cn', 'string' )
        Dag.createPlug( self.mobject, 'controlType', 'ct', 'string' )
        Dag.createPlug( self.mobject, 'controlCvs', 'ccvs', 'string' )
        Dag.createPlug( self.mobject, 'jointName', 'jn', 'string' )
        Dag.createPlug( self.mobject, 'parentProxy', 'pp', 'string' )
        Dag.createPlug( self.mobject, 'moduleRoot', 'mr', 'string' )
        
        # Set plug defaults.
        plug = Dag.getPlugByName( self.mobject, 'moduleRoot' )
        Dag.setPlugValue( plug, self.module_root )
                        
    def createCompound( self, poly_objects ):
        '''
        Merges curve shapes into one transform node. The final transform node
        is that of the first curve in the list of curves.
        
        @param poly_objects: List. Strings of object names or MObjects of objects.
        @return: Node Class.
        '''
        if isinstance( poly_objects, list ):
            # Put each polygon object to a Node class.
            poly_nodes = [] 
            
            for obj in poly_objects:
                if isinstance( obj, str ) or isinstance( obj, OpenMaya.MObject ):
                    poly_nodes.append( Node.Node( obj ) )
            
            if poly_nodes:
                # Each poly object will be moved to the transform node of the first
                # poly object in the list.
                transform_node = poly_nodes[0]
                
                for poly_node in poly_nodes:
                    poly_dagpath = poly_node.asDagPath()
                    
                    for child in xrange( poly_dagpath.childCount() ):
                        child_mobject = poly_dagpath.child( child )
                        child_node = Node.Node( child_mobject )
                        child_dagpath = child_node.asDagPath()
                        
                        if child_dagpath.apiType() == OpenMaya.MFn.kMesh: 
                            # We only do reparenting on poly objects not already a child
                            # of the transformNode.
                            childParent = child_node.getParent()
                            
                            if childParent.name != transform_node.name:
                                # Do the final parenting of the polygon shape to the
                                # target transform node.
                                dagMod = OpenMaya.MDagModifier()
                                dagMod.reparentNode( child_node.asMObject(), transform_node.asMObject() )
                                dagMod.doIt()
                
                # Delete the remaining transform nodes.
                for nodeIDX in xrange( 1, len( poly_nodes ) ):
                    OpenMaya.MGlobal.deleteNode( poly_nodes[nodeIDX].asMObject() )
                
                # Return a Node of the final polygon object.
                return transform_node
    
    def createShaders( self ):
        '''
        Creates the surface shaders used by the marker.
        '''
        shaders = {'marker_body':[0.090,0.506,0.569],
                   'marker_x':[1.0,0.0,0.0],
                   'marker_y':[0.0,1.0,0.0],
                   'marker_z':[0.0,0.0,1.0]}
        
        # Get a list of shaders that don't exist and need to be
        # created.
        make_shaders = []
        if not Dag.objExists( 'marker_body' ):
            make_shaders.append( 'marker_body' )
        
        if not Dag.objExists( 'marker_x' ):
            make_shaders.append( 'marker_x' )
        
        if not Dag.objExists( 'marker_y' ):
            make_shaders.append( 'marker_y' )
        
        if not Dag.objExists( 'marker_z' ):
            make_shaders.append( 'marker_z' )
            
        # Create any needed shaders.
        for name in make_shaders:
            # Maker the shader.
            mel_command = 'shadingNode -asShader surfaceShader'
            shader_name = OpenMaya.MGlobal.executeCommandStringResult( mel_command )
            shader_mobject = Dag.getMObject( shader_name )
            
            # Rename the shader.
            mdg_mod = OpenMaya.MDGModifier()
            mdg_mod.renameNode( shader_mobject, name )
            mdg_mod.doIt()
            
            # Create a shading group and connect the shader to it.
            shading_group_name = '{0}SG'.format( name )
            if not Dag.objExists( '{0}SG'.format( name ) ):
                # -empty seems to be busted for MEL. Only works with Python.
                #mel_command = 'sets -name {0}SG -empty true -renderable true -noSurfaceShader true'.format( name )
                #shading_group_name = OpenMaya.MGlobal.executeCommandStringResult( mel_command )
                CMDS.sets( name=shading_group_name, empty=True, renderable=True, noSurfaceShader=True )
                
            shading_group_mobject = Dag.getMObject( shading_group_name )
            
            Dag.connectNodes( shader_mobject, 'outColor', shading_group_mobject, 'surfaceShader' )
            
            # Set the shader color.
            out_color_plug = Dag.getPlugByName( shader_mobject, 'outColor' )
            Dag.setPlugValue( out_color_plug, shaders[name] )
    
    def setShapeColor( self, mesh_mobject, color_type ):
        '''
        Sets the color of the shape.
        '''
        mesh_mdagpath = Dag.getDagPath( mesh_mobject )
        
        for child in xrange( mesh_mdagpath.childCount() ):
            child_mobject = mesh_mdagpath.child( child )
            child_node = Node.Node( child_mobject )
            child_dagpath = child_node.asDagPath()
                                    
            if child_dagpath.apiType() == OpenMaya.MFn.kMesh:
                mel_command = 'sets -e -forceElement marker_{0}SG {1};'.format( color_type, child_dagpath.fullPathName() )
                OpenMaya.MGlobal.executeCommand( mel_command )
                
    def setControl( self ):
        '''
        Sets the control type and CV values
        '''
        pass
    
    def updatePointAxis( self ):
        '''
        Makes one axis longer than the others. The longer axis points
        to the marker that represents the next joint/control in the hierarchy.
        '''
        pass